"""
Flask文件管理和存储示例 - 展示文件上传、下载、存储管理等功能
包含本地存储、云存储、文件处理、安全检查等特性
"""

from flask import Flask, request, jsonify, send_file, g
import os
import sys
import time
import json
import hashlib
import mimetypes
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional, BinaryIO
from enum import Enum
from dataclasses import dataclass, asdict
import shutil
from pathlib import Path
import tempfile
from PIL import Image
import magic
from werkzeug.utils import secure_filename
from werkzeug.datastructures import FileStorage

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python_backend_toolkit.auth import JWTAuth
from python_backend_toolkit.cache import CacheManager, MemoryCache
from python_backend_toolkit.database import Base, BaseModel, DatabaseSession
from python_backend_toolkit.logging import get_logger, setup_logging
from python_backend_toolkit.http_client import HTTPClient
from python_backend_toolkit.utils import generate_uuid, format_datetime
from python_backend_toolkit.api.responses import (
    SuccessResponse, ErrorResponse, CreatedResponse
)
from python_backend_toolkit.api.exceptions import (
    ValidationError, NotFoundError, UnauthorizedError
)

from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, BigInteger, Enum as SQLEnum


# ========================================================================
# 数据模型和枚举
# ========================================================================

class FileType(Enum):
    """文件类型"""
    IMAGE = "image"
    DOCUMENT = "document"
    VIDEO = "video"
    AUDIO = "audio"
    ARCHIVE = "archive"
    OTHER = "other"


class StorageType(Enum):
    """存储类型"""
    LOCAL = "local"
    CLOUD = "cloud"
    TEMP = "temp"


class FileStatus(Enum):
    """文件状态"""
    UPLOADING = "uploading"
    UPLOADED = "uploaded"
    PROCESSING = "processing"
    READY = "ready"
    ERROR = "error"
    DELETED = "deleted"


@dataclass
class FileInfo:
    """文件信息"""
    file_id: str
    filename: str
    original_filename: str
    file_type: FileType
    mime_type: str
    size: int
    storage_type: StorageType
    storage_path: str
    url: str = None
    thumbnail_url: str = None
    metadata: Dict[str, Any] = None
    
    def to_dict(self):
        data = asdict(self)
        data['file_type'] = self.file_type.value
        data['storage_type'] = self.storage_type.value
        return data


class FileRecord(BaseModel):
    """文件记录模型"""
    __tablename__ = 'file_records'
    
    file_id = Column(String(50), unique=True, nullable=False)
    filename = Column(String(255), nullable=False)
    original_filename = Column(String(255), nullable=False)
    file_type = Column(SQLEnum(FileType), nullable=False)
    mime_type = Column(String(100), nullable=False)
    size = Column(BigInteger, nullable=False)
    storage_type = Column(SQLEnum(StorageType), nullable=False)
    storage_path = Column(String(500), nullable=False)
    url = Column(String(500))
    thumbnail_url = Column(String(500))
    metadata = Column(Text)  # JSON格式的元数据
    status = Column(SQLEnum(FileStatus), default=FileStatus.UPLOADING)
    upload_ip = Column(String(45))
    user_id = Column(String(50))
    download_count = Column(Integer, default=0)
    last_accessed = Column(DateTime)


class FileChunk(BaseModel):
    """文件分片模型（用于大文件上传）"""
    __tablename__ = 'file_chunks'
    
    chunk_id = Column(String(50), unique=True, nullable=False)
    file_id = Column(String(50), nullable=False)
    chunk_number = Column(Integer, nullable=False)
    chunk_size = Column(Integer, nullable=False)
    chunk_hash = Column(String(64), nullable=False)
    storage_path = Column(String(500), nullable=False)
    is_uploaded = Column(Boolean, default=False)


# ========================================================================
# 文件管理器
# ========================================================================

class FileManager:
    """文件管理器"""
    
    def __init__(self, upload_dir: str = "uploads", max_file_size: int = 100 * 1024 * 1024):
        self.upload_dir = Path(upload_dir)
        self.max_file_size = max_file_size
        self.logger = get_logger("FileManager")
        self.cache = MemoryCache()
        
        # 创建上传目录
        self.upload_dir.mkdir(parents=True, exist_ok=True)
        
        # 创建子目录
        for subdir in ['images', 'documents', 'videos', 'audios', 'archives', 'others', 'thumbnails', 'temp']:
            (self.upload_dir / subdir).mkdir(exist_ok=True)
        
        # 初始化数据库
        self.db_session = DatabaseSession(
            database_url="sqlite:///file_storage.db",
            echo=False
        )
        self.db_session.create_tables()
        
        # 支持的文件类型
        self.allowed_extensions = {
            FileType.IMAGE: {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'},
            FileType.DOCUMENT: {'.pdf', '.doc', '.docx', '.txt', '.rtf', '.odt', '.xls', '.xlsx', '.ppt', '.pptx'},
            FileType.VIDEO: {'.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.mkv'},
            FileType.AUDIO: {'.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma'},
            FileType.ARCHIVE: {'.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'},
        }
        
        # MIME类型映射
        self.mime_type_mapping = {
            '.jpg': 'image/jpeg',
            '.jpeg': 'image/jpeg',
            '.png': 'image/png',
            '.gif': 'image/gif',
            '.pdf': 'application/pdf',
            '.txt': 'text/plain',
            '.mp4': 'video/mp4',
            '.mp3': 'audio/mpeg',
            '.zip': 'application/zip',
        }
    
    def get_file_type(self, filename: str) -> FileType:
        """根据文件名获取文件类型"""
        ext = Path(filename).suffix.lower()
        
        for file_type, extensions in self.allowed_extensions.items():
            if ext in extensions:
                return file_type
        
        return FileType.OTHER
    
    def validate_file(self, file: FileStorage) -> Dict[str, Any]:
        """验证文件"""
        errors = []
        
        # 检查文件是否存在
        if not file or not file.filename:
            errors.append("No file provided")
            return {"valid": False, "errors": errors}
        
        # 检查文件大小
        file.seek(0, 2)  # 移动到文件末尾
        file_size = file.tell()
        file.seek(0)  # 重置到开头
        
        if file_size > self.max_file_size:
            errors.append(f"File size exceeds maximum limit ({self.max_file_size} bytes)")
        
        if file_size == 0:
            errors.append("File is empty")
        
        # 检查文件扩展名
        file_type = self.get_file_type(file.filename)
        ext = Path(file.filename).suffix.lower()
        
        if file_type == FileType.OTHER and ext not in ['.txt', '.log']:
            errors.append(f"File type '{ext}' is not allowed")
        
        # 检查MIME类型（如果可能）
        try:
            # 读取文件头部分析MIME类型
            file_header = file.read(1024)
            file.seek(0)
            
            detected_mime = magic.from_buffer(file_header, mime=True)
            expected_mime = self.mime_type_mapping.get(ext)
            
            if expected_mime and detected_mime != expected_mime:
                self.logger.warning(
                    "MIME type mismatch",
                    filename=file.filename,
                    expected=expected_mime,
                    detected=detected_mime
                )
        except Exception as e:
            self.logger.warning("MIME type detection failed", error=str(e))
        
        return {
            "valid": len(errors) == 0,
            "errors": errors,
            "file_type": file_type,
            "file_size": file_size
        }
    
    def upload_file(self, file: FileStorage, user_id: str = None, 
                   custom_filename: str = None) -> FileInfo:
        """上传文件"""
        # 验证文件
        validation = self.validate_file(file)
        if not validation["valid"]:
            raise ValidationError(f"File validation failed: {', '.join(validation['errors'])}")
        
        file_type = validation["file_type"]
        file_size = validation["file_size"]
        
        # 生成文件ID和安全文件名
        file_id = generate_uuid()
        original_filename = file.filename
        
        if custom_filename:
            filename = secure_filename(custom_filename)
        else:
            # 保持原始扩展名，但生成新的文件名
            ext = Path(original_filename).suffix
            filename = f"{file_id}{ext}"
        
        # 确定存储路径
        type_dir = self._get_type_directory(file_type)
        storage_path = self.upload_dir / type_dir / filename
        
        # 确保目录存在
        storage_path.parent.mkdir(parents=True, exist_ok=True)
        
        # 保存文件
        try:
            file.save(str(storage_path))
            
            # 计算文件哈希
            file_hash = self._calculate_file_hash(storage_path)
            
            # 获取MIME类型
            mime_type = mimetypes.guess_type(str(storage_path))[0] or 'application/octet-stream'
            
            # 提取元数据
            metadata = self._extract_metadata(storage_path, file_type)
            
            # 生成缩略图（如果是图片）
            thumbnail_url = None
            if file_type == FileType.IMAGE:
                thumbnail_url = self._generate_thumbnail(storage_path, file_id)
            
            # 保存到数据库
            session = self.db_session.get_session()
            
            try:
                file_record = FileRecord(
                    file_id=file_id,
                    filename=filename,
                    original_filename=original_filename,
                    file_type=file_type,
                    mime_type=mime_type,
                    size=file_size,
                    storage_type=StorageType.LOCAL,
                    storage_path=str(storage_path),
                    url=f"/files/{file_id}",
                    thumbnail_url=thumbnail_url,
                    metadata=json.dumps(metadata) if metadata else None,
                    status=FileStatus.READY,
                    user_id=user_id,
                    upload_ip=request.remote_addr if request else None
                )
                
                session.add(file_record)
                session.commit()
                
                self.logger.info(
                    "File uploaded successfully",
                    file_id=file_id,
                    filename=filename,
                    size=file_size,
                    type=file_type.value
                )
                
                return FileInfo(
                    file_id=file_id,
                    filename=filename,
                    original_filename=original_filename,
                    file_type=file_type,
                    mime_type=mime_type,
                    size=file_size,
                    storage_type=StorageType.LOCAL,
                    storage_path=str(storage_path),
                    url=f"/files/{file_id}",
                    thumbnail_url=thumbnail_url,
                    metadata=metadata
                )
                
            finally:
                session.close()
                
        except Exception as e:
            # 清理已上传的文件
            if storage_path.exists():
                storage_path.unlink()
            
            self.logger.error("File upload failed", error=str(e))
            raise
    
    def _get_type_directory(self, file_type: FileType) -> str:
        """获取文件类型对应的目录"""
        type_dirs = {
            FileType.IMAGE: 'images',
            FileType.DOCUMENT: 'documents',
            FileType.VIDEO: 'videos',
            FileType.AUDIO: 'audios',
            FileType.ARCHIVE: 'archives',
            FileType.OTHER: 'others'
        }
        return type_dirs.get(file_type, 'others')
    
    def _calculate_file_hash(self, file_path: Path) -> str:
        """计算文件哈希"""
        hash_md5 = hashlib.md5()
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()
    
    def _extract_metadata(self, file_path: Path, file_type: FileType) -> Dict[str, Any]:
        """提取文件元数据"""
        metadata = {}
        
        try:
            if file_type == FileType.IMAGE:
                # 提取图片元数据
                with Image.open(file_path) as img:
                    metadata.update({
                        "width": img.width,
                        "height": img.height,
                        "format": img.format,
                        "mode": img.mode
                    })
                    
                    # 提取EXIF信息
                    if hasattr(img, '_getexif') and img._getexif():
                        exif = img._getexif()
                        if exif:
                            metadata["exif"] = {k: str(v) for k, v in exif.items() if isinstance(v, (str, int, float))}
            
            # 添加文件系统信息
            stat = file_path.stat()
            metadata.update({
                "created_at": datetime.fromtimestamp(stat.st_ctime).isoformat(),
                "modified_at": datetime.fromtimestamp(stat.st_mtime).isoformat(),
                "file_hash": self._calculate_file_hash(file_path)
            })
            
        except Exception as e:
            self.logger.warning("Failed to extract metadata", error=str(e))
        
        return metadata
    
    def _generate_thumbnail(self, file_path: Path, file_id: str) -> Optional[str]:
        """生成缩略图"""
        try:
            thumbnail_dir = self.upload_dir / 'thumbnails'
            thumbnail_path = thumbnail_dir / f"{file_id}_thumb.jpg"
            
            with Image.open(file_path) as img:
                # 转换为RGB模式（如果需要）
                if img.mode in ('RGBA', 'LA', 'P'):
                    img = img.convert('RGB')
                
                # 生成缩略图
                img.thumbnail((200, 200), Image.Resampling.LANCZOS)
                img.save(thumbnail_path, 'JPEG', quality=85)
                
                return f"/thumbnails/{file_id}"
                
        except Exception as e:
            self.logger.warning("Failed to generate thumbnail", error=str(e))
            return None
    
    def get_file_info(self, file_id: str) -> Optional[FileInfo]:
        """获取文件信息"""
        session = self.db_session.get_session()
        
        try:
            file_record = session.query(FileRecord).filter(
                FileRecord.file_id == file_id
            ).first()
            
            if not file_record:
                return None
            
            metadata = None
            if file_record.metadata:
                try:
                    metadata = json.loads(file_record.metadata)
                except json.JSONDecodeError:
                    pass
            
            return FileInfo(
                file_id=file_record.file_id,
                filename=file_record.filename,
                original_filename=file_record.original_filename,
                file_type=file_record.file_type,
                mime_type=file_record.mime_type,
                size=file_record.size,
                storage_type=file_record.storage_type,
                storage_path=file_record.storage_path,
                url=file_record.url,
                thumbnail_url=file_record.thumbnail_url,
                metadata=metadata
            )
            
        finally:
            session.close()
    
    def get_file_path(self, file_id: str) -> Optional[Path]:
        """获取文件路径"""
        file_info = self.get_file_info(file_id)
        if not file_info:
            return None
        
        file_path = Path(file_info.storage_path)
        if not file_path.exists():
            self.logger.warning("File not found on disk", file_id=file_id, path=str(file_path))
            return None
        
        return file_path
    
    def delete_file(self, file_id: str) -> bool:
        """删除文件"""
        session = self.db_session.get_session()
        
        try:
            file_record = session.query(FileRecord).filter(
                FileRecord.file_id == file_id
            ).first()
            
            if not file_record:
                return False
            
            # 删除物理文件
            file_path = Path(file_record.storage_path)
            if file_path.exists():
                file_path.unlink()
            
            # 删除缩略图
            if file_record.thumbnail_url:
                thumbnail_path = self.upload_dir / 'thumbnails' / f"{file_id}_thumb.jpg"
                if thumbnail_path.exists():
                    thumbnail_path.unlink()
            
            # 更新数据库状态
            file_record.status = FileStatus.DELETED
            session.commit()
            
            self.logger.info("File deleted", file_id=file_id)
            return True
            
        except Exception as e:
            self.logger.error("Failed to delete file", file_id=file_id, error=str(e))
            return False
        finally:
            session.close()
    
    def update_download_count(self, file_id: str):
        """更新下载计数"""
        session = self.db_session.get_session()
        
        try:
            file_record = session.query(FileRecord).filter(
                FileRecord.file_id == file_id
            ).first()
            
            if file_record:
                file_record.download_count += 1
                file_record.last_accessed = datetime.utcnow()
                session.commit()
                
        finally:
            session.close()
    
    def get_file_list(self, user_id: str = None, file_type: FileType = None, 
                     limit: int = 50, offset: int = 0) -> List[Dict]:
        """获取文件列表"""
        session = self.db_session.get_session()
        
        try:
            query = session.query(FileRecord).filter(
                FileRecord.status != FileStatus.DELETED
            )
            
            if user_id:
                query = query.filter(FileRecord.user_id == user_id)
            
            if file_type:
                query = query.filter(FileRecord.file_type == file_type)
            
            files = query.order_by(FileRecord.created_at.desc()).offset(offset).limit(limit).all()
            
            result = []
            for file_record in files:
                data = {
                    "file_id": file_record.file_id,
                    "filename": file_record.filename,
                    "original_filename": file_record.original_filename,
                    "file_type": file_record.file_type.value,
                    "mime_type": file_record.mime_type,
                    "size": file_record.size,
                    "url": file_record.url,
                    "thumbnail_url": file_record.thumbnail_url,
                    "download_count": file_record.download_count,
                    "created_at": file_record.created_at.isoformat(),
                    "last_accessed": file_record.last_accessed.isoformat() if file_record.last_accessed else None
                }
                
                if file_record.metadata:
                    try:
                        data["metadata"] = json.loads(file_record.metadata)
                    except json.JSONDecodeError:
                        pass
                
                result.append(data)
            
            return result
            
        finally:
            session.close()
    
    def cleanup_temp_files(self, max_age_hours: int = 24):
        """清理临时文件"""
        temp_dir = self.upload_dir / 'temp'
        cutoff_time = datetime.utcnow() - timedelta(hours=max_age_hours)
        
        cleaned_count = 0
        
        for file_path in temp_dir.iterdir():
            if file_path.is_file():
                file_time = datetime.fromtimestamp(file_path.stat().st_mtime)
                if file_time < cutoff_time:
                    try:
                        file_path.unlink()
                        cleaned_count += 1
                    except Exception as e:
                        self.logger.warning("Failed to delete temp file", path=str(file_path), error=str(e))
        
        self.logger.info("Temp files cleanup completed", cleaned_count=cleaned_count)
        return cleaned_count
    
    def get_storage_stats(self) -> Dict[str, Any]:
        """获取存储统计"""
        session = self.db_session.get_session()
        
        try:
            # 文件数量统计
            total_files = session.query(FileRecord).filter(
                FileRecord.status != FileStatus.DELETED
            ).count()
            
            # 按类型统计
            type_stats = {}
            for file_type in FileType:
                count = session.query(FileRecord).filter(
                    FileRecord.file_type == file_type,
                    FileRecord.status != FileStatus.DELETED
                ).count()
                type_stats[file_type.value] = count
            
            # 存储大小统计
            total_size = session.query(
                session.query(FileRecord.size).filter(
                    FileRecord.status != FileStatus.DELETED
                ).subquery().c.size
            ).scalar() or 0
            
            # 磁盘使用情况
            disk_usage = shutil.disk_usage(self.upload_dir)
            
            return {
                "total_files": total_files,
                "type_stats": type_stats,
                "total_size": total_size,
                "total_size_mb": round(total_size / (1024 * 1024), 2),
                "disk_usage": {
                    "total": disk_usage.total,
                    "used": disk_usage.used,
                    "free": disk_usage.free,
                    "total_gb": round(disk_usage.total / (1024 ** 3), 2),
                    "used_gb": round(disk_usage.used / (1024 ** 3), 2),
                    "free_gb": round(disk_usage.free / (1024 ** 3), 2)
                }
            }
            
        finally:
            session.close()


# ========================================================================
# Flask应用
# ========================================================================

def create_file_storage_app() -> Flask:
    """创建文件存储应用"""
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'file-storage-demo-secret'
    app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024  # 100MB
    
    # 初始化日志
    setup_logging()
    logger = get_logger("FileStorageApp")
    
    # 初始化组件
    jwt_auth = JWTAuth(secret_key=app.config['SECRET_KEY'])
    file_manager = FileManager(upload_dir="uploads", max_file_size=100 * 1024 * 1024)
    
    # 中间件
    @app.before_request
    def before_request():
        g.request_id = generate_uuid()
        g.start_time = time.time()
        
        logger.info(
            "Request started",
            request_id=g.request_id,
            method=request.method,
            path=request.path
        )
    
    @app.after_request
    def after_request(response):
        duration = time.time() - g.start_time
        
        logger.info(
            "Request completed",
            request_id=g.request_id,
            status_code=response.status_code,
            duration=duration
        )
        
        return response
    
    # 异常处理
    @app.errorhandler(ValidationError)
    def handle_validation_error(e):
        return jsonify(ErrorResponse.create(message=str(e)).dict()), 400
    
    @app.errorhandler(NotFoundError)
    def handle_not_found_error(e):
        return jsonify(ErrorResponse.create(message=str(e)).dict()), 404
    
    @app.errorhandler(413)
    def handle_file_too_large(e):
        return jsonify(ErrorResponse.create(
            message="File too large"
        ).dict()), 413
    
    # ========================================================================
    # 文件上传API
    # ========================================================================
    
    @app.route('/upload', methods=['POST'])
    def upload_file():
        """上传文件"""
        try:
            if 'file' not in request.files:
                raise ValidationError("No file provided")
            
            file = request.files['file']
            user_id = request.form.get('user_id')
            custom_filename = request.form.get('filename')
            
            file_info = file_manager.upload_file(
                file=file,
                user_id=user_id,
                custom_filename=custom_filename
            )
            
            response = CreatedResponse.create(
                data={"file": file_info.to_dict()},
                message="File uploaded successfully"
            )
            return jsonify(response.dict()), 201
            
        except ValidationError as e:
            raise
        except Exception as e:
            logger.error("Upload file error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to upload file"
            ).dict()), 500
    
    @app.route('/upload/multiple', methods=['POST'])
    def upload_multiple_files():
        """批量上传文件"""
        try:
            files = request.files.getlist('files')
            if not files:
                raise ValidationError("No files provided")
            
            user_id = request.form.get('user_id')
            results = []
            errors = []
            
            for file in files:
                try:
                    file_info = file_manager.upload_file(
                        file=file,
                        user_id=user_id
                    )
                    results.append(file_info.to_dict())
                except Exception as e:
                    errors.append({
                        "filename": file.filename,
                        "error": str(e)
                    })
            
            response_data = {
                "uploaded_files": results,
                "upload_count": len(results),
                "error_count": len(errors)
            }
            
            if errors:
                response_data["errors"] = errors
            
            response = SuccessResponse.create(
                data=response_data,
                message=f"Uploaded {len(results)} files successfully"
            )
            return jsonify(response.dict())
            
        except ValidationError as e:
            raise
        except Exception as e:
            logger.error("Upload multiple files error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to upload files"
            ).dict()), 500
    
    # ========================================================================
    # 文件下载API
    # ========================================================================
    
    @app.route('/files/<file_id>', methods=['GET'])
    def download_file(file_id: str):
        """下载文件"""
        try:
            file_path = file_manager.get_file_path(file_id)
            if not file_path:
                raise NotFoundError("File not found")
            
            file_info = file_manager.get_file_info(file_id)
            
            # 更新下载计数
            file_manager.update_download_count(file_id)
            
            return send_file(
                str(file_path),
                as_attachment=True,
                download_name=file_info.original_filename,
                mimetype=file_info.mime_type
            )
            
        except NotFoundError as e:
            raise
        except Exception as e:
            logger.error("Download file error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to download file"
            ).dict()), 500
    
    @app.route('/files/<file_id>/view', methods=['GET'])
    def view_file(file_id: str):
        """在线查看文件"""
        try:
            file_path = file_manager.get_file_path(file_id)
            if not file_path:
                raise NotFoundError("File not found")
            
            file_info = file_manager.get_file_info(file_id)
            
            # 更新访问计数
            file_manager.update_download_count(file_id)
            
            return send_file(
                str(file_path),
                as_attachment=False,
                mimetype=file_info.mime_type
            )
            
        except NotFoundError as e:
            raise
        except Exception as e:
            logger.error("View file error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to view file"
            ).dict()), 500
    
    @app.route('/thumbnails/<file_id>', methods=['GET'])
    def get_thumbnail(file_id: str):
        """获取缩略图"""
        try:
            thumbnail_path = file_manager.upload_dir / 'thumbnails' / f"{file_id}_thumb.jpg"
            
            if not thumbnail_path.exists():
                raise NotFoundError("Thumbnail not found")
            
            return send_file(
                str(thumbnail_path),
                mimetype='image/jpeg'
            )
            
        except NotFoundError as e:
            raise
        except Exception as e:
            logger.error("Get thumbnail error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to get thumbnail"
            ).dict()), 500
    
    # ========================================================================
    # 文件管理API
    # ========================================================================
    
    @app.route('/files/<file_id>/info', methods=['GET'])
    def get_file_info(file_id: str):
        """获取文件信息"""
        try:
            file_info = file_manager.get_file_info(file_id)
            if not file_info:
                raise NotFoundError("File not found")
            
            response = SuccessResponse.create(
                data={"file": file_info.to_dict()},
                message="File info retrieved successfully"
            )
            return jsonify(response.dict())
            
        except NotFoundError as e:
            raise
        except Exception as e:
            logger.error("Get file info error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to get file info"
            ).dict()), 500
    
    @app.route('/files/<file_id>', methods=['DELETE'])
    def delete_file(file_id: str):
        """删除文件"""
        try:
            success = file_manager.delete_file(file_id)
            if not success:
                raise NotFoundError("File not found")
            
            response = SuccessResponse.create(
                message="File deleted successfully"
            )
            return jsonify(response.dict())
            
        except NotFoundError as e:
            raise
        except Exception as e:
            logger.error("Delete file error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to delete file"
            ).dict()), 500
    
    @app.route('/files', methods=['GET'])
    def get_file_list():
        """获取文件列表"""
        try:
            user_id = request.args.get('user_id')
            file_type_str = request.args.get('type')
            limit = min(int(request.args.get('limit', 50)), 100)
            offset = int(request.args.get('offset', 0))
            
            file_type = None
            if file_type_str:
                try:
                    file_type = FileType(file_type_str)
                except ValueError:
                    raise ValidationError("Invalid file type")
            
            files = file_manager.get_file_list(
                user_id=user_id,
                file_type=file_type,
                limit=limit,
                offset=offset
            )
            
            response = SuccessResponse.create(
                data={
                    "files": files,
                    "count": len(files),
                    "limit": limit,
                    "offset": offset
                },
                message="File list retrieved successfully"
            )
            return jsonify(response.dict())
            
        except ValidationError as e:
            raise
        except Exception as e:
            logger.error("Get file list error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to get file list"
            ).dict()), 500
    
    # ========================================================================
    # 存储管理API
    # ========================================================================
    
    @app.route('/storage/stats', methods=['GET'])
    def get_storage_stats():
        """获取存储统计"""
        try:
            stats = file_manager.get_storage_stats()
            
            response = SuccessResponse.create(
                data={"storage_stats": stats},
                message="Storage statistics retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Get storage stats error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to get storage statistics"
            ).dict()), 500
    
    @app.route('/storage/cleanup', methods=['POST'])
    def cleanup_storage():
        """清理存储"""
        try:
            data = request.get_json() or {}
            max_age_hours = data.get('max_age_hours', 24)
            
            cleaned_count = file_manager.cleanup_temp_files(max_age_hours)
            
            response = SuccessResponse.create(
                data={"cleaned_files": cleaned_count},
                message=f"Cleaned {cleaned_count} temporary files"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Cleanup storage error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to cleanup storage"
            ).dict()), 500
    
    # ========================================================================
    # 文件处理API
    # ========================================================================
    
    @app.route('/files/<file_id>/resize', methods=['POST'])
    def resize_image(file_id: str):
        """调整图片大小"""
        try:
            file_info = file_manager.get_file_info(file_id)
            if not file_info or file_info.file_type != FileType.IMAGE:
                raise NotFoundError("Image file not found")
            
            data = request.get_json()
            width = data.get('width', 800)
            height = data.get('height', 600)
            
            file_path = Path(file_info.storage_path)
            
            # 创建调整大小后的图片
            with Image.open(file_path) as img:
                resized_img = img.resize((width, height), Image.Resampling.LANCZOS)
                
                # 保存到临时文件
                temp_path = file_manager.upload_dir / 'temp' / f"{file_id}_resized_{width}x{height}.jpg"
                resized_img.save(temp_path, 'JPEG', quality=90)
                
                # 返回临时文件
                return send_file(
                    str(temp_path),
                    as_attachment=True,
                    download_name=f"resized_{file_info.original_filename}",
                    mimetype='image/jpeg'
                )
                
        except NotFoundError as e:
            raise
        except Exception as e:
            logger.error("Resize image error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to resize image"
            ).dict()), 500
    
    @app.route('/files/<file_id>/convert', methods=['POST'])
    def convert_image_format(file_id: str):
        """转换图片格式"""
        try:
            file_info = file_manager.get_file_info(file_id)
            if not file_info or file_info.file_type != FileType.IMAGE:
                raise NotFoundError("Image file not found")
            
            data = request.get_json()
            target_format = data.get('format', 'JPEG').upper()
            
            if target_format not in ['JPEG', 'PNG', 'WEBP', 'BMP']:
                raise ValidationError("Unsupported format")
            
            file_path = Path(file_info.storage_path)
            
            # 转换图片格式
            with Image.open(file_path) as img:
                if target_format == 'JPEG' and img.mode in ('RGBA', 'LA', 'P'):
                    img = img.convert('RGB')
                
                # 保存到临时文件
                ext = '.jpg' if target_format == 'JPEG' else f'.{target_format.lower()}'
                temp_path = file_manager.upload_dir / 'temp' / f"{file_id}_converted{ext}"
                
                img.save(temp_path, target_format, quality=90 if target_format == 'JPEG' else None)
                
                # 返回临时文件
                return send_file(
                    str(temp_path),
                    as_attachment=True,
                    download_name=f"converted_{Path(file_info.original_filename).stem}{ext}",
                    mimetype=f'image/{target_format.lower()}'
                )
                
        except (NotFoundError, ValidationError) as e:
            raise
        except Exception as e:
            logger.error("Convert image format error", file_id=file_id, error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to convert image format"
            ).dict()), 500
    
    # ========================================================================
    # 健康检查和信息API
    # ========================================================================
    
    @app.route('/health', methods=['GET'])
    def health_check():
        """健康检查"""
        return jsonify({
            "status": "healthy",
            "timestamp": datetime.utcnow().isoformat(),
            "storage": {
                "upload_dir": str(file_manager.upload_dir),
                "max_file_size": file_manager.max_file_size,
                "max_file_size_mb": round(file_manager.max_file_size / (1024 * 1024), 2)
            }
        })
    
    @app.route('/info', methods=['GET'])
    def app_info():
        """应用信息"""
        return jsonify({
            "name": "File Management and Storage Demo",
            "version": "1.0.0",
            "description": "文件管理和存储示例 - 文件上传、下载、存储管理等功能",
            "features": [
                "文件上传下载",
                "批量文件处理",
                "文件类型检测",
                "缩略图生成",
                "图片处理",
                "存储统计",
                "文件安全检查",
                "元数据提取"
            ],
            "supported_file_types": {
                "images": list(file_manager.allowed_extensions[FileType.IMAGE]),
                "documents": list(file_manager.allowed_extensions[FileType.DOCUMENT]),
                "videos": list(file_manager.allowed_extensions[FileType.VIDEO]),
                "audios": list(file_manager.allowed_extensions[FileType.AUDIO]),
                "archives": list(file_manager.allowed_extensions[FileType.ARCHIVE])
            },
            "endpoints": {
                "upload": [
                    "POST /upload - 上传单个文件",
                    "POST /upload/multiple - 批量上传文件"
                ],
                "download": [
                    "GET /files/<id> - 下载文件",
                    "GET /files/<id>/view - 在线查看文件",
                    "GET /thumbnails/<id> - 获取缩略图"
                ],
                "management": [
                    "GET /files/<id>/info - 获取文件信息",
                    "DELETE /files/<id> - 删除文件",
                    "GET /files - 获取文件列表"
                ],
                "storage": [
                    "GET /storage/stats - 获取存储统计",
                    "POST /storage/cleanup - 清理存储"
                ],
                "processing": [
                    "POST /files/<id>/resize - 调整图片大小",
                    "POST /files/<id>/convert - 转换图片格式"
                ]
            }
        })
    
    return app


if __name__ == '__main__':
    app = create_file_storage_app()
    
    print("=" * 60)
    print("Flask File Management and Storage Demo")
    print("=" * 60)
    print("文件管理和存储演示:")
    print("  功能特性:")
    print("    - 文件上传下载")
    print("    - 批量文件处理")
    print("    - 文件类型检测和验证")
    print("    - 自动缩略图生成")
    print("    - 图片处理（调整大小、格式转换）")
    print("    - 存储统计和管理")
    print("    - 文件安全检查")
    print("    - 元数据提取")
    print("    - 下载计数统计")
    print()
    print("  支持的文件类型:")
    print("    - 图片: JPG, PNG, GIF, BMP, WEBP, SVG")
    print("    - 文档: PDF, DOC, DOCX, TXT, RTF, XLS, XLSX, PPT, PPTX")
    print("    - 视频: MP4, AVI, MOV, WMV, FLV, WEBM, MKV")
    print("    - 音频: MP3, WAV, FLAC, AAC, OGG, WMA")
    print("    - 压缩包: ZIP, RAR, 7Z, TAR, GZ, BZ2")
    print()
    print("  API端点:")
    print("    文件上传:")
    print("      POST /upload - 上传单个文件")
    print("      POST /upload/multiple - 批量上传文件")
    print("    文件下载:")
    print("      GET /files/<id> - 下载文件")
    print("      GET /files/<id>/view - 在线查看文件")
    print("      GET /thumbnails/<id> - 获取缩略图")
    print("    文件管理:")
    print("      GET /files/<id>/info - 获取文件信息")
    print("      DELETE /files/<id> - 删除文件")
    print("      GET /files - 获取文件列表")
    print("    存储管理:")
    print("      GET /storage/stats - 获取存储统计")
    print("      POST /storage/cleanup - 清理存储")
    print("    文件处理:")
    print("      POST /files/<id>/resize - 调整图片大小")
    print("      POST /files/<id>/convert - 转换图片格式")
    print("=" * 60)
    
    app.run(
        host='0.0.0.0',
        port=5015,
        debug=True
    )